"""
利用伴随矩阵法，初等行变换法，LU分解法求解逆矩阵，程序包含输入矩阵的验证，计算过程中的关键步骤。
"""
import numpy as np
# 定义抽象类方法
class inverse_matrix:
    def input_matrix(self): #输入矩阵
        pass
    def check_matrix(self): #验证矩阵是否可逆
        pass
    def adjoint_matrix(self): #伴随矩阵法计算逆矩阵
        pass
    def elementary_row_transform(self): #初等行变换法计算逆矩阵
        pass
    def LU_decomposition(self): #LU分解法计算逆矩阵
        pass


# 定义具体类继承抽象类该类实现矩阵的输入，以及矩阵是否可逆的验证
class get_check_matrix_from_user(inverse_matrix):
    def input_matrix(self):# 矩阵输入
        matrix = []
        try:# 防止用户输入非数字元素
            # 提示用户输入矩阵的行数和列数
            row = int(input("请输入矩阵的行数："))
            col = int(input("请输入矩阵的列数："))
            if row != col: # 初步验证要输入的矩阵是否为可逆
                print("要输入的矩阵不是方阵，无法计算逆矩阵！")
                return None
            for i in range(row):
                row_data = []
                for j in range(col):
                    while True:# 输入矩阵的元素
                        try:
                            element = float(input("请输入第{}行第{}列的元素：".format(i+1, j+1)))
                            row_data.append(element)
                            break
                        except ValueError:# 防止用户误输入非数字元素
                            print("输入有误，请重新输入！")
                matrix.append(row_data)
            return matrix
        except ValueError:
                print("输入有误，请重新输入！")
                return None
    # 继续验证该方阵是否为可逆矩阵(行列式的值是否为0)
    def check_matrix(self, matrix):
        if np.linalg.det(matrix) == 0:
            print("该矩阵行列式的值为0不可逆！")
        else:
            print(f"该矩阵行列式的值为{np.linalg.det(matrix)},不为0，可逆！")
# 定义具体类继承抽象类，该类实现伴随矩阵法，初等行变换法，LU分解法计算逆矩阵
class calculate_inverse_matrix(inverse_matrix):
    def __init__(self, matrix):
        self.matrix = np.array(matrix)
        self.n = len(self.matrix)
    # 伴随矩阵法计算逆矩阵
    def adjoint_matrix(self):
        # 计算该方阵行列式的值
        D = np.linalg.det(self.matrix)
        # 计算该方阵的伴随矩阵
        n = self.n
        adj_matrix = np.empty((n, n), dtype=int)
        for i in range(n):
            for j in range(n):
                # 计算代数余子式
                minor = np.delete(np.delete(self.matrix, i, axis=0), j, axis=1)
                cofactor = (-1) ** (i + j) * np.linalg.det(minor)
                adj_matrix[j, i] = cofactor
        # 计算该方阵的逆矩阵
        inv_matrix = adj_matrix / D
        # 打印结果
        print(f"使用伴随矩阵法计算得出该方阵的逆矩阵为：\n{inv_matrix}")
        return inv_matrix
    # 初等行变换法计算逆矩阵
    def elementary_row_transform(self):
        # 构造增广矩阵
        extended_matrix = np.hstack((self.matrix, np.eye(len(self.matrix))))
        #np.eye(len(matrix)) 生成一个与 matrix 行数相同的单位矩阵。单位矩阵是一个对角线元素为1，其余元素为0的方阵。
        #np.hstack 是 NumPy 库中的一个函数，用于在水平方向（列方向）上拼接数组或矩阵。
        # 对增广矩阵进行初等行变换
        for i in range(len(self.matrix)):
            # 将第 i 行的第i个元素变为 1
            extended_matrix[i] = extended_matrix[i] / extended_matrix[i][i]
            # 将第 i 列的其他元素变为 0
            for j in range(len(self.matrix)):
                if i == j:
                    continue
                elif i != j:
                    extended_matrix[j] = extended_matrix[i]*(-1*(extended_matrix[j][i])) + extended_matrix[j]
        # 提取逆矩阵
        # 对于二维数组（即矩阵），我们可以使用逗号来分隔行和列的切片
        inv_matrix = extended_matrix[:, len(self.matrix):]
        # 打印结果
        print(f"使用初等行变换法计算得出该方阵的逆矩阵为：\n{inv_matrix}")
        return inv_matrix
    # LU分解法计算逆矩阵
    def LU_decomposition(self):
        # 初始化L和U矩阵
        L = np.eye(self.n)
        U = np.copy(self.matrix)
        # LU分解
        for i in range(self.n):
            # 主元归一化
            pivot = U[i, i]
            if pivot == 0:
                raise ValueError("矩阵不可逆，存在零主元")
            L[i, i] = pivot
            U[i, :] /= pivot
            for j in range(i + 1, self.n):
                factor = U[j, i]
                L[j, i] = factor
                U[j, :] -= factor * U[i, :]
        # 计算逆矩阵
        L_inv = np.linalg.inv(L)
        U_inv = np.linalg.inv(U)
        inv_matrix = np.dot(U_inv, L_inv)
        # 打印结果
        print(f"使用LU分解法计算得出该方阵的逆矩阵为：\n{inv_matrix}")
        return inv_matrix
# 定义主协调类，实现所有功能
class main():
    def __init__(self):
        self.matrix = get_check_matrix_from_user().input_matrix()
        # 如果矩阵为空，则先输入矩阵
        if self.matrix == None:
            print("矩阵为空，请先输入矩阵")
            self.matrix = get_check_matrix_from_user().input_matrix()
        # 如果矩阵不为空，则继续验证矩阵是否可逆
        else:
            get_check_matrix_from_user().check_matrix(self.matrix)
            # 如果矩阵可逆，则继续计算逆矩阵
            if np.linalg.det(self.matrix) != 0:
                print("方阵行列式不为0，矩阵可逆")
                self.calculate_inverse_matrix = calculate_inverse_matrix(self.matrix)
                print("请选择计算逆矩阵的方法：")
                print("输入“1” 伴随矩阵法")
                print("输入“2” 初等行变换法")
                print("输入“3” LU分解法")
                choice = input("请输入您的选择：")
                if choice == "1":
                    self.calculate_inverse_matrix.adjoint_matrix()
                elif choice == "2":
                    self.calculate_inverse_matrix.elementary_row_transform()
                elif choice == "3":
                    self.calculate_inverse_matrix.LU_decomposition()
                else:
                    print("输入错误，请重新输入")
                    self.__init__()
                # 如果矩阵不可逆，则重新输入矩阵
            else:
                print("方阵行列式为0，矩阵不可逆，请重新输入矩阵")
                self.__init__()

if __name__ == '__main__':
    main()


